<?xml version="1.0" encoding="UTF-8"?>
<!--
	Copyright 2009 Barnaby@iWare.co.uk
	
	Licensed under the Apache License, Version 2.0 (the "License"); you
	may not use this file except in compliance with the License. You may
	obtain a copy of the License at
	http://www.apache.org/licenses/LICENSE-2.0 Unless required by
	applicable law or agreed to in writing, software distributed under the
	License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
	CONDITIONS OF ANY KIND, either express or implied. See the License for
	the specific language governing permissions and limitations under the
	License.
-->
<xsl:stylesheet
	version="2.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:ss="uri:simple-service.iware.co.uk"
	xmlns:wsdl2="http://www.w3.org/ns/wsdl"
	xmlns:whttp="http://www.w3.org/ns/wsdl/http"
	xmlns:xs="http://www.w3.org/2001/XMLSchema"
	exclude-result-prefixes="ss"
>
	<!-- <xsl:import-schema>iware.simple-service.xsd</xsl:import-schema> -->
	<xsl:output
		indent="yes"
	/>
	
	<xsl:param name="repeat" select="3" xs:type="integer" />
		
	<xsl:template match="/">
		<xsl:variable name="package" select="string-join(reverse(tokenize(ss:iware/@package,'\.')),'.')" />
		<xsl:variable name="out" select="substring-before(document-uri(.),'.xml')" />
		<xsl:result-document href="{$out}.xsd">
			<xs:schema 
				targetNamespace="http://{$package}/xsd"
			>
				<xsl:namespace name="msg">
					<xsl:text>http://</xsl:text>
					<xsl:value-of select="$package" />
					<xsl:text>/xsd</xsl:text>
				</xsl:namespace>
				<xsl:apply-templates select="ss:iware/*" mode="xsd"/>
			</xs:schema>
		</xsl:result-document>
		
		<wsdl2:description
			targetNamespace="http://{$package}"
		>
			<xsl:namespace name="tns">
				<xsl:text>http://</xsl:text>
				<xsl:value-of select="$package" />
			</xsl:namespace>
			<xsl:namespace name="msg">
				<xsl:text>http://</xsl:text>
				<xsl:value-of select="$package" />
				<xsl:text>/xsd</xsl:text>
			</xsl:namespace>
			<xsl:apply-templates select="ss:iware/comment()" />
			<wsdl2:types>
				<xs:import
					namespace="http://{$package}/xsd"
					schemaLocation="{tokenize($out,'/')[last()]}.xsd"
				/>
			</wsdl2:types>
			<xsl:apply-templates select="ss:iware/*"/>
		</wsdl2:description>
	</xsl:template>
	
	<xsl:template match="node()" />
	
	<xsl:template match="comment()" priority="2">
		<wsdl2:documentation>
			<xsl:value-of select="." />
		</wsdl2:documentation>
	</xsl:template>
	
	<xsl:template match="ss:interface">
		<wsdl2:interface name="{@name}">
			<xsl:apply-templates />
		</wsdl2:interface>
	</xsl:template>
	
	<xsl:template match="ss:operation">
		<wsdl2:operation
			name="{@name}"
			pattern="http://www.w3.org/ns/wsdl/in-out" 
			style="http://www.w3.org/ns/wsdl/style/iri"
		>
			<xsl:apply-templates />
			<wsdl2:input element="msg:{@name}Request" />
			<wsdl2:output element="msg:{@name}Response" />
		</wsdl2:operation>
	</xsl:template>
	
	<xsl:template match="ss:service">
		<wsdl2:binding
			name="{@name}HTTPBinding"
			type="http://www.w3.org/ns/wsdl/http"
			interface="tns:{@interface}"
			whttp:methodDefault="GET"
		>
			<wsdl2:documentation>
				<xsl:text> Binding for service '</xsl:text>
				<xsl:value-of select="@name" />
				<xsl:text>'. </xsl:text>
			</wsdl2:documentation>
			<xsl:variable name="interface" select="@interface" />
			<xsl:for-each select="//ss:interface[@name=$interface]/ss:operation">
				<wsdl2:operation>
					<xsl:attribute name="ref">
						<xsl:text>tns:</xsl:text>
						<xsl:value-of select="@name" />
					</xsl:attribute>
				</wsdl2:operation>
			</xsl:for-each>
		</wsdl2:binding>
		
		<wsdl2:service
			name="{@name}"
			interface="tns:{@interface}"
		>
			<xsl:apply-templates />
			<wsdl2:endpoint
				name="{@name}Endpoint"
				binding="tns:{@name}HTTPBinding"
				address="{@href}"
			>
			</wsdl2:endpoint>
		</wsdl2:service>
	</xsl:template>
	
	<xsl:template match="node()" mode="xsd" />
	
	<xsl:template match="comment()" mode="xsd" priority="2">
		<xs:annotation>
			<xs:documentation>
				<xsl:value-of select="." />
			</xs:documentation>
		</xs:annotation>
	</xsl:template>
	
	<xsl:template match="ss:import" mode="xsd">
		<xs:import schemaLocation="{.}" />
	</xsl:template>
	<xsl:template match="ss:interface | ss:operation" mode="xsd">
		<xsl:apply-templates select="*" mode="xsd" />
	</xsl:template>
	
	<xsl:template match="ss:in" mode="xsd">
		<xs:element name="{../@name}Request">
			<xs:annotation>
				<xs:documentation>
					<xsl:text> Arguments for '</xsl:text>
					<xsl:value-of select="../@name" />
					<xsl:text>' operation. </xsl:text>
				</xs:documentation>
			</xs:annotation>
			<xs:complexType>
				<xs:all>
					<xsl:apply-templates mode="xsd" />
				</xs:all>
			</xs:complexType>
		</xs:element>
	</xsl:template>
	
	<xsl:template match="ss:out" mode="xsd">
		<xs:element name="{../@name}Response">
			<xs:annotation>
				<xs:documentation>
					<xsl:text> Return for '</xsl:text>
					<xsl:value-of select="../@name" />
					<xsl:text>' operation. </xsl:text>
				</xs:documentation>
			</xs:annotation>
			<xs:complexType>
				<xs:all>
					<xsl:apply-templates mode="xsd" />
				</xs:all>
			</xs:complexType>
		</xs:element>
	</xsl:template>
	
	<!-- HACK: de-dupe params -->
	<xsl:template match="ss:param[@name=preceding-sibling::ss:param/@name]" mode="xsd" />
	<xsl:template match="ss:param[@name=parent::ss:repeated/preceding-sibling::ss:repeated/ss:param/@name]" mode="xsd" />
	
	<xsl:template match="ss:param" mode="xsd">
		<xsl:param name="repeat_id" select="''" xs:type="string" />
		<xs:element>
			<xsl:if test="@name">
				<xsl:attribute name="name">
					<xsl:value-of select="@name" />
					<xsl:value-of select="$repeat_id" />
				</xsl:attribute>
			</xsl:if>
			<xsl:copy-of select="@default" />
			<xsl:if test="@max">
				<xsl:attribute name="maxOccurs">
					<xsl:value-of select="@max" />
				</xsl:attribute>
			</xsl:if>
			<xsl:if test="@min!=1">
				<xsl:attribute name="minOccurs">
					<xsl:value-of select="@min" />
				</xsl:attribute>
			</xsl:if>
			<xsl:if test="not(@min) and not(@default) and not(parent::ss:iware)">
				<xsl:attribute name="minOccurs">0</xsl:attribute>
			</xsl:if>
			<xsl:if test="not(@type='none') and not(ss:*) and not(@ref)">
				<xsl:attribute name="type">
					<xsl:value-of select="@type" />
					<xsl:if test="not(@type)">
						<xsl:text>xs:string</xsl:text>
					</xsl:if>
				</xsl:attribute>
			</xsl:if>
			<xsl:copy-of select="@ref" />
			<xsl:apply-templates select="comment()" mode="xsd" />
			<xsl:if test="ss:*">
				<xs:complexType>
					<xsl:if test="@sub='sequence'">
						<xs:sequence>
							<xsl:apply-templates select="*" mode="xsd">
								<xsl:with-param name="repeat_id" select="$repeat_id" />
							</xsl:apply-templates>
						</xs:sequence>
					</xsl:if>
					<xsl:if test="not(@sub='sequence')">
						<xs:all>
							<xsl:apply-templates select="*" mode="xsd">
								<xsl:with-param name="repeat_id" select="$repeat_id" />
							</xsl:apply-templates>
						</xs:all>
					</xsl:if>
				</xs:complexType>
			</xsl:if>
		</xs:element>
	</xsl:template>
	
	<xsl:template match="ss:repeated" mode="xsd">
		<!-- HACK: A workaround for Enoms silly XML. -->
		<xsl:variable name="buf" select="node()" />
		<xsl:if test=".//@min">
			<xsl:message terminate="no">Repeating required paramiters is very unlikly to be what you intended!</xsl:message>
		</xsl:if>
		<xsl:for-each select="1 to $repeat">
			<xsl:apply-templates select="$buf" mode="xsd">
				<xsl:with-param name="repeat_id" select="." />
			</xsl:apply-templates>
		</xsl:for-each>
	</xsl:template>
	
	<xsl:template match="ss:group" mode="xsd">
		<xs:group>
			<xsl:copy-of select="@*" />
			<xsl:apply-templates select="node()" />
		</xs:group>
	</xsl:template>
	
	<xsl:template match="ss:type" mode="xsd">
		<xs:complexType>
			<xsl:copy-of select="@name" />
			<xsl:if test="@sub='sequence'">
				<xs:sequence>
					<xsl:apply-templates select="*" mode="xsd" />
				</xs:sequence>
			</xsl:if>
			<xsl:if test="not(@sub='sequence')">
				<xs:all>
					<xsl:apply-templates select="*" mode="xsd" />
				</xs:all>
			</xsl:if>
		</xs:complexType>
	</xsl:template>
	
	<xsl:template match="ss:reuse[@ref]" mode="xsd">
		<!-- HACK: A workaround for xsd:group not being nestable in xsl:all. -->
		<xsl:apply-templates select="id(@ref)/node()" mode="xsd" />
	</xsl:template>

</xsl:stylesheet>
